# @Time  :2021/5/27 21:57
# @Author: Houtaroy
from typing import List
from dataclasses import dataclass

from werkzeug.security import generate_password_hash

from flask_koala.core.database import db
from flask_koala.core.domain import AuditEntity
from flask_koala.core.exceptions import BusinessException

from .utils import TreeNode

user_role = db.Table('t_user_role',
                     db.Column('user_id', db.BIGINT, db.ForeignKey('t_user.id')),
                     db.Column('role_id', db.BIGINT, db.ForeignKey('t_role.id'))
                     )

role_permission = db.Table('t_role_permission',
                           db.Column('role_id', db.BIGINT, db.ForeignKey('t_role.id')),
                           db.Column('permission_id', db.BIGINT, db.ForeignKey('t_permission.id'))
                           )

permission_api = db.Table('t_permission_api',
                          db.Column('permission_id', db.BIGINT, db.ForeignKey('t_permission.id')),
                          db.Column('api_id', db.BIGINT, db.ForeignKey('t_api.id'))
                          )


@dataclass
class Api(AuditEntity):
    """
    接口数据实体类
    """
    __tablename__ = 't_api'

    code: str = db.Column(db.String(50), nullable=False)
    name: str = db.Column(db.String(50), nullable=False)
    description: str = db.Column(db.String(200))
    url: str = db.Column(db.String(1024), nullable=False)
    method: str = db.Column(db.String(50), nullable=False)
    sort_index: int = db.Column(db.Integer)


@dataclass
class Permission(AuditEntity):
    """
    权限数据实体类
    """
    __tablename__ = 't_permission'

    parent_id: int = db.Column(db.BIGINT, db.ForeignKey('t_permission.id'))
    code: str = db.Column(db.String(50), nullable=False)
    name: str = db.Column(db.String(50), nullable=False)
    description: str = db.Column(db.String(200))
    url: str = db.Column(db.String(1024))
    icon: str = db.Column(db.String(200))
    sort_index: int = db.Column(db.Integer)


@dataclass
class PermissionDTO(TreeNode, Permission):
    """
    权限数据传输类
    """
    children: List = db.relationship('PermissionDTO')
    apis: List[Api] = db.relationship('Api', secondary=permission_api, lazy='immediate')

    def __hash__(self):
        return hash(f"{self.__class__.__module__}.{self.__class__.__name__}.{self.id}")


@dataclass
class Role(AuditEntity):
    """
    角色数据实体类
    """
    __tablename__ = 't_role'

    code: str = db.Column(db.String(50), nullable=False)
    name: str = db.Column(db.String(50), nullable=False)
    description: str = db.Column(db.String(200))
    sort_index: str = db.Column(db.Integer)


@dataclass
class RoleDTO(Role):
    permissions: List[PermissionDTO] = db.relationship('PermissionDTO', secondary=role_permission)


@dataclass
class User(AuditEntity):
    """
    用户数据实体类
    """
    __tablename__ = 't_user'

    username: str = db.Column(db.String(200), nullable=False, comment="用户名")
    password: str = db.Column(db.String(1024), nullable=False, comment="密码")
    name: str = db.Column(db.String(50), nullable=False, comment="昵称")
    gender: int = db.Column(db.Integer, default=0, comment="性别")
    email: str = db.Column(db.String(200), comment="邮箱")
    phone: str = db.Column(db.String(50), comment="联系电话")
    sort_index: int = db.Column(db.Integer, comment="排序索引")
    roles: List[Role] = db.relationship('Role', secondary=user_role)

    @classmethod
    def get_by_username(cls, username: str):
        user = cls.query.filter_by(username=username).first()
        if user is None:
            raise BusinessException('资源不存在')
        return user

    @classmethod
    def add(cls, data: dict):
        data['password'] = generate_password_hash(data['password'])
        if 'roles' in data:
            data['roles'] = list(filter(None, [Role.get_by_id(item['id']) for item in data['roles']]))
        return super().add(data)

    @classmethod
    def update(cls, id, data):
        if 'password' in data:
            del data['password']
        if 'roles' in data:
            data['roles'] = list(filter(None, [Role.get_by_id(item['id']) for item in data['roles']]))
        super().update(id, data)


@dataclass
class UserDTO(User):
    """
    用户数据传输类
    """
    roles: List[RoleDTO] = db.relationship('RoleDTO', secondary=user_role)
